﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Speakup;
using WebLayer;
using System.IO;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Runtime.Serialization;
using TableParsers;

namespace Frontend
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    partial class MainWindow : Window, IStateSerializable 
    {
        ClassList SpeakupClassList = new ClassList();
        PersonalStats SpeakupPersonalStats = new PersonalStats();
        ClassPanelList ClassPanelList = new ClassPanelList();
        Refresher Refresher = new Refresher();
        
        public MainWindow()
        {
            InitializeComponent();

            ClassPanelList.CollectionChanged += ClassPanelList_CollectionChanged;
            ClassPanelList.SelectionChanged += ClassPanelList_SelectionChanged;
            ClassPanelList.HighlightChanged += ClassPanelList_HighlightChanged;

            SpeakupClassList.CollectionChanged += SpeakupClassList_CollectionChanged;
            SpeakupClassList.ClassStatusChanged += SpeakupClassList_ClassStatusChanged;

            ClassTypeFilterPanel.Changed += ClassTypeFilterPanel_Changed;
            DateTimeFilterPanel.Changed += DateTimeFilterPanel_Changed;
            
            Refresher.StateChanged += Refresher_StateChanged;

            SpeakupPersonalStats.Refreshed += SpeakupPersonalStats_Refreshed;
            Week.CurrentWeekChanged += Week_CurrentWeekChanged;

            LoadPersonalStats();
            LoadClassList();
            LoadUIState();            

            WeeksControl.CurrentWeek = Week.CurrentWeek;
            WeeksControl.Stats = SpeakupPersonalStats;
            WeeksControl.RefreshGrids();

            CurrentUnitTextBlock.Text = SpeakupPersonalStats.Unit.ToString();
            CurrentLevelTextBlock.Text = SpeakupPersonalStats.Level.ToString();
            CurrentWeekTextBlock.Text = Week.CurrentWeek.ToString();
        }

        void LoadClassList()
        {
            try
            {
                SpeakupClassList.Reload();
            }
            catch (IOException)
            {
                Trace.TraceWarning("Failed to load speakup classes list from file.");
            }
        }
        void SaveClassList()
        {
            try
            {
                SpeakupClassList.Save();
            }
            catch (IOException)
            {
                Trace.TraceWarning("Failed to save speakup classes list to file.");
            }
        }
        void LoadPersonalStats()
        {
            try
            {
                SpeakupPersonalStats.Reload();
            }
            catch (IOException)
            {
                Trace.TraceWarning("Failed to load speakup personal stats from file.");
            }
        }
        void SavePersonalStats()
        {
            try
            {
                SpeakupPersonalStats.Save();
            }
            catch (IOException)
            {
                Trace.TraceWarning("Failed to save speakup personal stats to file.");
            }
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            base.OnClosing(e);
            SavePersonalStats();
            SaveClassList();
            SaveUIState();
        }

        /// <summary>
        /// Sync panel list with existing class list.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void SpeakupClassList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (Speakup.Class speakupClass in e.NewItems)
                {
                    ClassPanelList.Add(new ClassPanel(speakupClass));
                    SyncWithTodoTab(speakupClass);
                }                
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (Speakup.Class speakupClass in e.OldItems)
                {
                    if (toCancelGrid.Classes.Contains(speakupClass))
                    {
                        toCancelGrid.Classes.Remove(speakupClass);
                    }

                    if (toReserveGrid.Classes.Contains(speakupClass))
                    {
                        toReserveGrid.Classes.Remove(speakupClass);
                    }

                    foreach (ClassPanel panel in ClassPanelList)
                    {
                        if (panel.SpeakupClass == speakupClass)
                        {
                            ClassPanelList.Remove(panel);
                            break;
                        }
                    }
                }
            }

            ClassCount.Text = SpeakupClassList.Count.ToString();
        }

        /// <summary>
        /// Sync time sheet and panel list
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ClassPanelList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (ClassPanel classPanel in e.NewItems)
                {
                    TimeSlot timeSlot = new TimeSlot(classPanel.SpeakupClass.ClassTime.Begin,
                                                 classPanel.SpeakupClass.ClassTime.End);

                    TimeSheet.SetTimeSlot(classPanel, timeSlot);
                    TimeSheet.SetDaySlot(classPanel, classPanel.SpeakupClass.ClassTime.Date);

                    ClassTimeSheet.AddChildren(classPanel);
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (ClassPanel classPanel in e.OldItems)
                {
                    ClassTimeSheet.RemoveChildren(classPanel);
                }
            }
        }

        void ClassPanelList_HighlightChanged(object sender, ClassPanelList.ClassChangedEventArgs e)
        {
            if (e.SpeakupClass == null)
            {
                Class speakupClass = null;
                if(ClassPanelList.SelectedItem != null) 
                {
                    speakupClass = ClassPanelList.SelectedItem.SpeakupClass;
                }

                ClassInfoPanel.Update(speakupClass);
            }
            else
            {
                ClassInfoPanel.Update(e.SpeakupClass);
            }
        }

        void ClassPanelList_SelectionChanged(object sender, ClassPanelList.ClassChangedEventArgs e)
        {
            ClassInfoPanel.Update(e.SpeakupClass);            
        }
        
        void SpeakupClassList_ClassStatusChanged(object sender, ClassStatusChangedArgs e)
        {
            SyncWithTodoTab(e.Source);            
        }

        private void LoginPanel_Refresh(object sender, LoginPanelRefreshEventArgs e)
        {

            if (Refresher.State == RefresherState.InPorgress)
            {
                Trace.TraceWarning("Refresh requested while refresh operation is in progress");
                return;
            }


            RefreshStatusPanel.Visibility = Visibility.Visible;
            RefreshCancelButton.IsEnabled = true;

            LoginPanel.IsRefreshing = true;            
            Refresher.StartRefresh(LoginPanel.User, LoginPanel.Password, ((int)LoginPanel.School).ToString(), SpeakupClassList);
        }

        void Refresher_StateChanged(object sender, RefresherStateEventArgs e)
        {
            LoginPanel.IsRefreshing = (e.Refresher.State == RefresherState.InPorgress);

            if (e.Refresher.State != RefresherState.InPorgress)
            {
                RefreshStatusPanel.Visibility = Visibility.Collapsed;
            }
            
            if (e.Refresher.State == RefresherState.Completed)
            {
                SaveClassList();
                SpeakupClassList.Clear();
                SpeakupClassList.Merge(e.Refresher.ClassList);
                SaveClassList();

                SavePersonalStats();
                if (SpeakupPersonalStats != null)
                {
                    SpeakupPersonalStats.Refresh(e.Refresher.PersonalStats);
                }
                else
                {
                    SpeakupPersonalStats = e.Refresher.PersonalStats;
                }
                SavePersonalStats();

                WeeksControl.Stats = SpeakupPersonalStats;
                WeeksControl.RefreshGrids();
            }
            else if (e.Refresher.State == RefresherState.ErrorOccured)
            {
                MessageBox.Show("Error occured during refresh:\n" + e.Refresher.ErrorMessage,
                                    "Refresh error", MessageBoxButton.OK, MessageBoxImage.Error);                
            }
            else if (e.Refresher.State == RefresherState.Cancelled)
            {
                MessageBox.Show("User cancelled refresh.", "Cancelled", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }            
        }

        void SpeakupPersonalStats_Refreshed(object sender, EventArgs e)
        {
            WeeksControl.CurrentLevel = SpeakupPersonalStats.Level;

            CurrentUnitTextBlock.Text = SpeakupPersonalStats.Unit.ToString();
            CurrentLevelTextBlock.Text = SpeakupPersonalStats.Level.ToString();
        }

        void Week_CurrentWeekChanged(object sender, EventArgs e)
        {
            WeeksControl.CurrentWeek = Week.CurrentWeek;
            CurrentWeekTextBlock.Text = Week.CurrentWeek.ToString();
        }

        private void RefreshCancel_Click(object sender, RoutedEventArgs e)
        {
            Refresher.CancelRefresh();
            RefreshCancelButton.IsEnabled = false;
        }
        
        void SyncWithTodoTab(Speakup.Class speakupClass)
        {
            if (speakupClass.IsStatusModified && speakupClass.IsReserved)
            {
                toReserveGrid.Classes.Add(speakupClass);
            }
            else
            {
                if (toReserveGrid.Classes.Contains(speakupClass))
                {
                    toReserveGrid.Classes.Remove(speakupClass);
                }
            }

            if (speakupClass.IsStatusModified && speakupClass.IsAvailable)
            {
                toCancelGrid.Classes.Add(speakupClass);
            }
            else
            {
                if (toCancelGrid.Classes.Contains(speakupClass))
                {
                    toCancelGrid.Classes.Remove(speakupClass);
                }
            }
        }
        
        void ClassTypeFilterPanel_Changed(object sender, EventArgs e)
        {
            ClassPanelList.UseManualMask = ClassTypeFilterPanel.UseManualFilter;

            ClassPanelMask mask = new ClassPanelMask();
            mask[ClassType.Club] = ClassTypeFilterPanel.HighlightClub;
            mask[ClassType.Conversation] = ClassTypeFilterPanel.HighlightConversation;
            mask[ClassType.Grammar] = ClassTypeFilterPanel.HighlightGrammar;
            mask[ClassType.Group] = ClassTypeFilterPanel.HighlightGroup;
            mask[ClassType.Reading] = ClassTypeFilterPanel.HighlightReading;
            mask[ClassType.Writing] = ClassTypeFilterPanel.HighlightWriting;

            ClassPanelList.ManualMask = mask;
            ClassPanelList.DefaultEnabledStatus = ClassTypeFilterPanel.HighlightOther;            
        }

        void DateTimeFilterPanel_Changed(object sender, DateAndTimeFilterEventArgs e)
        {
            if (e.IsFilterEnabled)
            {
                ClassTimeSheet.UpdateDate(e.DateBegin, e.DateEnd);
                ClassTimeSheet.UpdateTime(e.TimeBegin, e.TimeEnd);                
            }
            else
            {
                ClassTimeSheet.UpdateDate(DateTime.Today,
                                          DateTime.Today + TimeSpan.FromDays(13));
                ClassTimeSheet.UpdateTime(TimeSpan.FromHours(8), TimeSpan.FromHours(22));
            }
        }

        private void ClearClasses_Click(object sender, RoutedEventArgs e)
        {
            SpeakupClassList.Clear();
            SaveClassList();
        }

        //ui persistence

        static readonly string UIStateFile = "UIState.bin";
        static readonly string ClassTypeFilterPanelStateKey = typeof(ClassTypeFilterPanel).Name;
        static readonly string DateTimeFilterPanelStateKey = typeof(DateTimeFilterPanel).Name;
        static readonly string LegendPanelStateKey = typeof(LegendPanel).Name;
        static readonly string LoginPanelStateKey = typeof(LoginPanel).Name;
        

        private void SaveUIState()
        {
            try
            {
                StateSerializer.SaveState(this, UIStateFile);
            }
            catch (Exception)
            {
                //just ignore the error.
                if (File.Exists(UIStateFile))
                {
                    File.Delete(UIStateFile);
                }
            }
        }
        private void LoadUIState()
        {
            try
            {
                if (File.Exists(UIStateFile))
                {
                    StateSerializer.LoadState(this, UIStateFile);
                }
            }
            catch (Exception)
            {
                if (File.Exists(UIStateFile))
                {
                    File.Delete(UIStateFile);
                }
            }
        }

        public StateDictionary GetState()
        {
            StateDictionary state = new StateDictionary();
            state.AddValue(ClassTypeFilterPanelStateKey, ClassTypeFilterPanel.GetState());
            state.AddValue(DateTimeFilterPanelStateKey, DateTimeFilterPanel.GetState());
            state.AddValue(LegendPanelStateKey, LegendPanel.GetState());
            state.AddValue(LoginPanelStateKey, LoginPanel.GetState());            
            
            return state;
        }

        public void SetState(StateDictionary state)
        {
            ClassTypeFilterPanel.SetState(state.GetState(ClassTypeFilterPanelStateKey));
            DateTimeFilterPanel.SetState(state.GetState(DateTimeFilterPanelStateKey));
            LegendPanel.SetState(state.GetState(LegendPanelStateKey));
            LoginPanel.SetState(state.GetState(LoginPanelStateKey));
        }
       
    }
}
